So far, the component has been doing the rendering loop for us. But this means that we are locked and cannot do anything specific during the rendering.
In this tutorial, we will see how we can make our own rendering loop. With this, we will be able to add some logic of our own to add some movement and improve on that static image the program is rendering.
While the component has its own running loop, it also offers ways to act on a per frame basis. Let's dig it and replace the call to the component's run method by our own loop. Include :
We introduce a new component in the equation : nkWinUi. Let's see why and how :
First, we gather the system singleton pointer to use them within the loop. We did not do anything like that up till now, but this is better to avoid useless getter redundant calls. We then retrieve the internal UI system it is using to also use it on our side.
Within the loop, we call the frame method. This takes the context we want to frame for, and runs the rendering operation once.
Then, we tick the system coming from nkWinUi. As we saw before, the window created comes from the nkWinUi component. As a result, we need it to process all events related to the UI. If we omit this call, we won't be able to close the window, for instance.
This loop runs while the graphics component is flagged as needing to run. In fact, the closing event is handled internally and turns this flag off, hinting us as to when we should stop the loop.
If you now run the program, you will notice that... Nothing changed. But this is good ! Now, we have a custom rendering loop, enabling us to inject some logic before each frame.
Let's get that static image moving ! Now that we have the possibility to do something in between frames, we will move the camera around to admire the sphere under different angles.
First, we need to retrieve the camera. Let's see how do do that :
Now we can get the camera we will work with, before entering our rendering loop :
As usual, camera have a dedicated manager with which you can create, get or erase them. However, there is a new keyword here : "default".
For each context, it is possible to specify a camera to use. Thus, the default camera is the one that will be used by default, when no camera is given to overwrite this behaviour.
Our context has no camera attached through the manager, and as such, the default camera will be used when rendering it.
So now we have the camera we need. What is left is to update its characteristics for each frame. Let's make a simple algorithm making the camera rotate around the sphere. We need another include :
As we will play with time, we need to have some chrono structures in there. With those include, let's prepare some variables before entering the rendering loop :
First is the time, in milliseconds, that we want a revolution around the sphere to take. We will go for a 5 seconds loop.
Next, we take a time reference to compare with.
Finally, we set our sphere to (0, 0, 10), so we keep that center in mind.
Now that we have some things ready, let's implement the logic within the loop itself :
There is some maths to take into account, but the code in itself, once understood, is quite straightforward.
To start with, we take the time point as we render, to be able to derive the total time, in milliseconds, since we started the rendering.
With this, we can get the T, between [0, 1], representing the percentage of the loop time we did since last loop. As we are going to work with cosinus and sinus, we reproject it between [-1, 1] and multiply it by pi.
The T can now be used to derive the position, by using trigonometry. We keep a distance of 10 from the sphere, and center it around the center of the sphere.
Final step is to communicate this to the camera. We move it absolutely, in the world, and update its direction by specifying the center of the sphere as the point to look at, with a steady Y up vector.
Now that the loop is augmented, let's compile and launch the program, to see its effect :
Before each loop, as we change the camera's position, we ultimately end up altering the final image, each frame... Having a nice and smooth animation like demonstrated. And this concludes this tutorial, our custom rendering loop is ready !